package com.tang.calculator;

import com.tang.calculator.annotation.Operate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.WebApplicationContext;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import sun.rmi.runtime.Log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName: AbstractProcessor
 * @Author: freedu
 * @Date: 2021/3/22 16:22
 * @Description: TODO
 * @Version: 1.0
 */
@Component
@Slf4j
public abstract class AbstractProcessor<T> {

    @Autowired
    private ConfigCalculator calculator;

    private ReentrantLock reentrantLock = new ReentrantLock();

    public void process(Context context) {
        if (!context.isEnd()) {
            doOperate(context);

            submitData(context);
        }
    }

    private void doOperate(Context context) {
        log.info("执行计算操作...");
        List<DataSource> dataSources = context.getDataSources();
        // 计算
        for (DataSource dataSource : dataSources) {
            try {
                calculator.executeConfig(dataSource.getConfigPath(),context.getType(), context.getOperate(), dataSource.getSource());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void submitData(Context context) {
        log.info("开始提交操作...");
        List<DataSource> dataSources = context.getDataSources();
        // 具体操作 如保存 更新等
        for (CalculateProcessor processor : context.getList()) {
            for (DataSource dataSource : dataSources) {
                doSubmitData(context, processor, dataSource);
            }
        }
    }

    private void doSubmitData(Context context, CalculateProcessor processor, DataSource dataSource) {
        // 获取子类泛型的类型
        Type actualTypeArgument = ((ParameterizedTypeImpl) processor.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        // 如果处理器泛型类型与datasource中类型一致 则去寻找可以调用的操作方法 如add edit等
        if (dataSource.getSourceType() == actualTypeArgument) {
            String operate = dataSource.getOperate();
            Method[] declaredMethods = ReflectionUtils.getDeclaredMethods(processor.getClass());
            for (Method method : declaredMethods) {
                Operate annotation = method.getAnnotation(Operate.class);
                // 找到方法 进行调用 加锁处理
                if (annotation != null && annotation.value().equals(operate)) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    for (Class<?> parameterType : parameterTypes) {
                        if (parameterType != Context.class) {
                            throw new RuntimeException("处理器:" + processor.getClass().getName() + "的" + method.getName() + "必须有一个Context类型参数!");
                        }
                    }
                    reentrantLock.lock();
                    try {
                        // TODO 这里加锁
                        method.setAccessible(true);
                        method.invoke(processor, context);
                        dataSource.setSubmitted(true);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    } finally {
                        reentrantLock.unlock();
                    }
                    break;
                } else {
                }
            }
        }
        context.setEnd(true);
    }
}
